package com.logic.landseaserver.service.impl;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.logic.common.exception.BusinessException;
import com.logic.common.security.SecurityUtils;
import com.logic.common.util.QueryUtil;
import com.logic.common.util.SysUtil;
import com.logic.landseaserver.common.LandeaConstants;
import com.logic.landseaserver.common.LandeaConstants.BillType;
import com.logic.landseaserver.common.LandeaConstants.ProduceType;
import com.logic.landseaserver.common.enums.BillStatusEnum;
import com.logic.landseaserver.common.exception.LandseaException;
import com.logic.landseaserver.common.util.StringTools;
import com.logic.landseaserver.domain.BalanceSheetRecord;
import com.logic.landseaserver.domain.Contract;
import com.logic.landseaserver.domain.RealBill;
import com.logic.landseaserver.domain.RealBillBalanceRecord;
import com.logic.landseaserver.domain.Room;
import com.logic.landseaserver.models.independent.service.BillIndependentService;
import com.logic.landseaserver.persistence.read.BalanceSheetRecordReadMapper;
import com.logic.landseaserver.persistence.read.ContractReadMapper;
import com.logic.landseaserver.persistence.read.RealBillReadMapper;
import com.logic.landseaserver.persistence.read.RoomReadMapper;
import com.logic.landseaserver.persistence.write.RealBillWriteMapper;
import com.logic.landseaserver.service.IRealBillService;
import com.logic.landseaserver.ws.dto.BillPaymentDTO;
import com.logic.landseaserver.ws.dto.RealBillDTO;
import com.logic.system.service.impl.FileService;

@Service
public class RealBillServiceImpl implements IRealBillService
{
    
    private static final Logger LOG = LoggerFactory.getLogger(RealBillServiceImpl.class);
    
    @Autowired
    private RealBillReadMapper realBillReadMapper;
    
    @Autowired
    private RealBillWriteMapper realBillWriteMapper;
    
    @Autowired
    private FileService fileService;
    
    @Autowired
    private ContractReadMapper contractReadMapper;
    
    @Autowired
    private BillIndependentService billIndependentService;
    
    @Autowired
    private BalanceSheetRecordReadMapper balanceSheetRecordReadMapper;
    
    @Autowired
    private RoomReadMapper roomReadMapper;
    
    @Override
    public void delete(String arg0)
        throws BusinessException
    {
        String[] idArr = arg0.split(",");
        for (String id : idArr)
        {
            Integer realBillId = Integer.valueOf(id);
            RealBill realBill = (RealBill)this.get(realBillId);
            Boolean pass = this.validateForDelete(realBill);
            if (pass)
            {
                realBill.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
                realBillWriteMapper.deleteByPrimaryKey(realBill);
            }
        }
        
    }
    
    @Override
    public Object get(Integer arg0)
        throws BusinessException
    {
        return realBillReadMapper.selectByPrimaryKey(arg0);
    }
    
    @Override
    public int insert(Object arg0)
        throws BusinessException
    {
        Integer id = -1;
        Boolean pass = this.validateForInsert(arg0);
        if (pass)
        {
            RealBill realBill = (RealBill)arg0;
            setDefaultValue(realBill);
            realBill.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
            realBillWriteMapper.insertSelective(realBill);
            id = realBill.getId();
            try
            {
                insertBalanceSheet(realBill);
            }
            catch (LandseaException e)
            {
                LOG.error("realBill|实时账单|实时账单同步更新失败.realBillId=" + realBill.getId());
            }
        }
        return id;
    }
    
    private void insertBalanceSheet(RealBill realBill)
        throws LandseaException
    {
        BalanceSheetRecord record = new BalanceSheetRecord();
        
        record.setBillId(realBill.getId());
        record.setBillNo(realBill.getBillNo());
        Contract contract = contractReadMapper.selectByPrimaryKey(realBill.getContractId());
        if (null != contract)
        {
            record.setContractNo(contract.getContractNo());
            record.setProjectId(contract.getProjectId());
            record.setRoomId(contract.getRoomId());
            record.setContractId(contract.getId());
            Room room = roomReadMapper.selectByPrimaryKey(contract.getRoomId());
            record.setHouseNum(room.getHouseNum());
        }
        record.setBillMonth(realBill.getBillMonth());
        record.setExpenditureCode(realBill.getExpenseType());
        String expenditure = balanceSheetRecordReadMapper.selectExpenditure(realBill.getExpenseType());
        record.setExpenditure(expenditure);
        record.setStartTime(realBill.getCreatedDtm());
        record.setEndTime(null);
        record.setReceivableMoney(realBill.getBillPrice());
        record.setAmountReceived(0.00);
        record.setMark(realBill.getComment());
        record.setBillStatus(BillStatusEnum.BIST3.getCode());
        record.setBillType("_BT3");
        record.setProduceType(ProduceType.PAY);
        billIndependentService.insertBalanceSheet(record);
        
    }
    
    private void setDefaultValue(RealBill realBill)
    {
        String dateString = SysUtil.convertDateToString(new Date(), "yyyyMM");
        realBill.setBillMonth(dateString);
        realBill.setStatus(BillStatusEnum.BIST3.getCode());// not pay
        Contract contract = contractReadMapper.selectByPrimaryKey(realBill.getContractId());
        Integer roomId = contract.getRoomId();
        realBill.setRoomId(roomId);
    }
    
    @Override
    public List<?> query(QueryUtil arg0)
    {
        return realBillReadMapper.getList(arg0);
    }
    
    @Override
    public void update(Object arg0)
        throws BusinessException
    {
        Boolean pass = this.validateForUpdate(arg0);
        if (pass)
        {
            RealBill realBill = (RealBill)arg0;
            realBill.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
            realBill.setCreatedBy(null);
            realBill.setCreatedDtm(null);
            realBillWriteMapper.updateByPrimaryKeySelective(realBill);
        }
        
    }
    
    @Override
    public Boolean validate(Object arg0)
        throws BusinessException
    {
        Boolean pass = true;
        return pass;
    }
    
    @Override
    public Boolean validateForDelete(Object arg0)
        throws BusinessException
    {
        return true;
    }
    
    @Override
    public Boolean validateForInsert(Object arg0)
        throws BusinessException
    {
        Boolean pass = false;
        pass = this.validate(arg0);
        return pass;
    }
    
    @Override
    public Boolean validateForUpdate(Object arg0)
        throws BusinessException
    {
        Boolean pass = false;
        pass = this.validate(arg0);
        return pass;
    }
    
    /**
     * 
     * [描述]：合同实时账单查询</br>
     *
     * @param queryUtil
     * @return
     *
     */
    @Override
    public List<RealBillDTO> queryDTO(QueryUtil queryUtil)
    {
        
        List<RealBillDTO> resultList = new ArrayList<RealBillDTO>();
        
        // 是否需要查询出勾销记录,只有其他费项才需要显示(支付、未支付都需要显示)
        Map<String, Object> reqParamMap = queryUtil.getParams();
        
        String needShowCancelBill = StringTools.getString(reqParamMap.get("needShowCancelBill"));
        // 紧急规避
        needShowCancelBill = "";
        String billStatus = StringTools.getString(reqParamMap.get("billStatus"));
        if (LandeaConstants.NEED_SHOW_CANCELBILL.equals(needShowCancelBill))
        {
            // 查询出所有的记录，包括被删除的
            List<RealBillBalanceRecord> list = realBillReadMapper.getDTOListWithBillCancel(queryUtil);
            if (CollectionUtils.isEmpty(list))
            {
                return resultList;
            }
            Map<String, Object> paramMap = new HashMap<String, Object>();
            // 此处查询的就是实时
            paramMap.put("billType", BillType.REALTIME_BILL);
            
            Map<String,List<Integer>> balanceIdMap = getMaxBalanceIdMap(list);
            
            for (RealBillBalanceRecord realBillBalanceRecord : list)
            {
                // 先判断是否被删除了
                if (realBillBalanceRecord.getDeleted())
                {
                    // 不允许勾销
                    realBillBalanceRecord.setId(null);
                    
                    // 从balance创建
                    RealBillDTO realBillDTO  =  realBillBalanceRecord.buildRealBillDTOFromBalance();
                    resultList.add(realBillDTO);
                    continue;
                }
                
                Integer bsBillId = realBillBalanceRecord.getBsBillId();
                String bsBillStatus = realBillBalanceRecord.getBsBillStatus();
                Integer bsProduceType = realBillBalanceRecord.getBsProduceType();
                // 未支付+支付类型
                if (BillStatusEnum.BIST3.getCode().equals(bsBillStatus) && ProduceType.PAY == bsProduceType.intValue())
                {
                    // 判断balanceId是否为最大,如果是，则realId保留，允许勾销
                    if (!isMaxId(balanceIdMap.get(String.valueOf(bsBillId)), realBillBalanceRecord.getBsId()))
                    {
                        // 不允许勾销
                        realBillBalanceRecord.setId(null);
                        // 从balance创建
                        RealBillDTO realBillDTO  =  realBillBalanceRecord.buildRealBillDTOFromBalance();
                        resultList.add(realBillDTO);
                    }
                    else
                    {
                        // 从realBill创建
                        RealBillDTO realBillDTO  =  realBillBalanceRecord.buildRealBillDTO();
                        resultList.add(realBillDTO);
                    }
                    continue;
                }
                
                // 不允许勾销
                realBillBalanceRecord.setId(null);
                
                // 从balance创建
                RealBillDTO realBillDTO  =  realBillBalanceRecord.buildRealBillDTOFromBalance();
                resultList.add(realBillDTO);
                
            }
            return resultList;
        }
        
        // 查询出所有的记录，包括被删除的
        List<RealBillDTO> list = realBillReadMapper.getDTOList(queryUtil);
        if (CollectionUtils.isEmpty(list))
        {
            return resultList;
        }        
        
        // 不需要显示勾销，直接查询
        for (RealBillDTO realBillDTO : list)
        {
            if (!realBillDTO.getDeleted())
            {
                setPaymentImages(realBillDTO);
                resultList.add(realBillDTO);
            }
        }
        
        return resultList;

    }
    
    @Override
    public RealBillDTO getDTO(Integer realBillId) {
        return realBillReadMapper.selectDTOByPrimaryKey(realBillId);
    }
    
    /**
     * 
     * [简要描述]：实时账单如果有支付图片则需要查询出</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-09-21)</br>
     *
     * @param realBillDTO
     *
     */
    private void setPaymentImages(RealBillDTO realBillDTO)
    {
        List<BillPaymentDTO> billPyamentList = realBillDTO.getBillPaymentList();
        if (CollectionUtils.isNotEmpty(billPyamentList))
        {
            for (BillPaymentDTO paymentDTO : realBillDTO.getBillPaymentList())
            {
                if (!StringUtils.isEmpty(paymentDTO.getImageId()))
                {
                    paymentDTO.setImagePath(fileService.getFilesByIds(paymentDTO.getImageId()));
                }
            }
        }
    }
    
    private void buildRealBillFromBalance(List<BalanceSheetRecord> balanceSheetRecords, Integer contractId, List<RealBillDTO> resultList)
    {
        RealBillDTO realBillBalance = null;
        for (BalanceSheetRecord balanceSheetRecord : balanceSheetRecords)
        {
            realBillBalance = new RealBillDTO();
            realBillBalance.setBillMonth(balanceSheetRecord.getBillMonth());
            realBillBalance.setBillNo(balanceSheetRecord.getBillNo());
            realBillBalance.setBillPrice(balanceSheetRecord.getReceivableMoney());
            realBillBalance.setComment(balanceSheetRecord.getMark());
            realBillBalance.setContractId(contractId);
            if (null != balanceSheetRecord.getCreateTime())
            {
                Timestamp tst = new Timestamp(balanceSheetRecord.getCreateTime().getTime());
                realBillBalance.setCreatedDtm(tst);
            }
            realBillBalance.setExpenseType(balanceSheetRecord.getExpenditureCode());
            realBillBalance.setExpenseTypeDesc(balanceSheetRecord.getExpenditure());
            realBillBalance.setLastModifiedBy(balanceSheetRecord.getLastModifiedBy());
            realBillBalance.setRoomId(balanceSheetRecord.getRoomId());
            realBillBalance.setStatus(balanceSheetRecord.getBillStatus());
            
            resultList.add(realBillBalance);
        }
    }
    
    private Map<String,List<Integer>> getMaxBalanceIdMap(List<RealBillBalanceRecord> list)
    {
        Map<String,List<Integer>> balaceIdMap = new HashMap<String,List<Integer>>();
        for (RealBillBalanceRecord realBillBalanceRecord : list)
        {
            List<Integer> balaceIdList = balaceIdMap.get(String.valueOf(realBillBalanceRecord.getId()));
            if (null == balaceIdList)
            {
                balaceIdList = new ArrayList<Integer>();
                balaceIdMap.put(String.valueOf(realBillBalanceRecord.getId()), balaceIdList);
            }
            
            if (!balaceIdList.contains(realBillBalanceRecord.getBsId()))
            {
                balaceIdList.add(realBillBalanceRecord.getBsId());
            }
        }
        
        return balaceIdMap;
    }
    
    /**
     * 
     * [简要描述]：判断IntList的最大值</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-09-26)</br>
     *
     * @param idList
     * @param id
     * @return
     *
     */
    private boolean isMaxId(List<Integer> idList, Integer id)
    {
        Integer maxInt = Collections.max(idList);
        return id.intValue() == maxInt.intValue();
    }
}
